#pragma once
#include "rpc_router.hpp"
#include <set>

namespace myrpc {
    namespace server {
        class ProviderManager {
        public:
            using ptr = std::shared_ptr<ProviderManager>;
            // 服务提供者结构体
            struct Provider {
                using ptr = std::shared_ptr<Provider>;
                std::mutex _mutex;
                BaseConnection::ptr _conn;          // 维护的连接
                Address _host;                      // 主机信息
                std::vector<std::string> _methods;  // 提供的所有服务

                Provider(const BaseConnection::ptr &conn, const Address &host)
                :_conn(conn),
                _host(host)
                {}
                void addMethod(const std::string &method){
                    std::unique_lock<std::mutex> lock(_mutex);
                    _methods.emplace_back(method);
                }
            };

            // 新的服务提供者进行服务注册的时候调用  
            Provider::ptr addProvider(const BaseConnection::ptr &conn, const Address &host, const std::string &method){
                Provider::ptr provider;
                {
                    std::unique_lock<std::mutex> lock(_mutex);
                    // 1.先获取该连接对应的服务提供者对象 没有则创建并建立映射关系
                    auto it = _conn_provider.find(conn);
                    if (it != _conn_provider.end()){
                        provider = it->second;
                    }
                    else{
                        provider = std::make_shared<Provider>(conn, host);
                        _conn_provider.insert(std::make_pair(conn, provider));
                    }
                    // 2.将服务提供者对象添加到给该服务管理的集合中
                    auto &providers = _method_providers[method];
                    providers.insert(provider);
                }
                // 3.服务提供者对象中增加新服务
                provider->addMethod(method);
                return provider;
            }
            // 当一个服务提供者断开连接后 需要获取它的相关信息——用于服务下线通知
            Provider::ptr getProvider(const BaseConnection::ptr &conn){
                std::unique_lock<std::mutex> lock(_mutex);
                auto it = _conn_provider.find(conn);
                if (it != _conn_provider.end()){
                    return it->second;
                }
                return Provider::ptr();
            }
            // 当一个服务提供者断开连接后 需要依次获取所有服务从集合中删除映射关系
            void delProvider(const BaseConnection::ptr &conn){
                std::unique_lock<std::mutex> lock(_mutex);
                auto it = _conn_provider.find(conn);
                if (it == _conn_provider.end()){
                    return;
                }
                Provider::ptr provider = it->second;
                for(auto &method : provider->_methods){
                    auto &providers = _method_providers[method];
                    providers.erase(provider);
                }
                _conn_provider.erase(it);
            }
            // 获取所有能够提供目标服务的主机信息
            std::vector<Address> methodHosts(const std::string &method){
                std::unique_lock<std::mutex> lock(_mutex);
                auto it = _method_providers.find(method);
                if (it == _method_providers.end()){
                    return std::vector<Address>();
                }
                // 遍历集合中的所有服务提供者 获取地址信息
                std::vector<Address> hosts;
                for(auto &provider : it->second){
                    hosts.push_back(provider->_host);
                }
                return hosts;
            }

        private:
            std::mutex _mutex;
            // 建立服务与提供者之间的映射关系 用来表示一个服务都有哪些服务提供者 一对多的关系
            std::unordered_map<std::string, std::set<Provider::ptr>> _method_providers;
            // 建立连接与提供者之间的映射关系 用来表示一个连接对应了哪个服务提供者 一对一的关系
            std::unordered_map<BaseConnection::ptr, Provider::ptr> _conn_provider;
        };  

        class DiscovererManager {
        public:
            using ptr = std::shared_ptr<DiscovererManager>;
            // 服务发现者结构体
            struct Discoverer {
                using ptr = std::shared_ptr<Discoverer>;
                std::mutex _mutex;
                BaseConnection::ptr _conn;            // 维护的连接
                std::vector<std::string> _methods;    // 发现的所有服务

                Discoverer(const BaseConnection::ptr &conn)
                :_conn(conn)
                {}
                void addMethod(const std::string &method){
                    std::unique_lock<std::mutex> lock(_mutex);
                    _methods.emplace_back(method);
                }
            };

            // 当每次客户端进行服务发现时新增服务发现者
            Discoverer::ptr addDiscoverer(const BaseConnection::ptr &conn, const std::string &method){
                Discoverer::ptr discoverer;
                {
                    std::unique_lock<std::mutex> lock(_mutex);
                    auto it = _conn_discoverer.find(conn);
                    if (it != _conn_discoverer.end()){
                        discoverer = it->second;
                    }
                    else{
                        discoverer = std::make_shared<Discoverer>(conn);
                        _conn_discoverer.insert(std::make_pair(conn, discoverer));
                    }
                    auto &discoverers = _method_discoverers[method];
                    discoverers.insert(discoverer);
                }
                discoverer->addMethod(method);
                return discoverer;
            }
            // 当服务发现者断开连接时从集合中删除
            void delDiscoverer(const BaseConnection::ptr &conn){
                std::unique_lock<std::mutex> lock(_mutex);
                auto it = _conn_discoverer.find(conn);
                if (it == _conn_discoverer.end()){
                    return;
                }
                Discoverer::ptr discoverer = it->second;
                for(auto &method : discoverer->_methods){
                    auto &discoverers = _method_discoverers[method];
                    discoverers.erase(discoverer);
                }
                _conn_discoverer.erase(it);
            }
            // 当有新的服务提供者上线服务时 通知之前所有发现过该服务的发现者 哪个主机也可以提供服务了
            void onlineNotify(const std::string &method, const Address &host){
                return notify(method, host, ServiceOpType::SERVICE_ONLINE);
            }
            // 当有服务提供者下线时 通知之前所有发现过该服务的发现者 哪个主机不能提供服务了
            void offlineNotify(const std::string &method, const Address &host){
                return notify(method, host, ServiceOpType::SERVICE_OFFLINE);
            }

        private:
            void notify(const std::string &method, const Address &host, const ServiceOpType &optype){
                std::unique_lock<std::mutex> lock(_mutex);
                auto it=_method_discoverers.find(method);
                if (it == _method_discoverers.end()){
                    return;
                }
                // 构建服务上线或下线请求并发送
                auto svr_req = MessageFactory::create<ServiceRequest>();
                svr_req->setMethod(method);
                svr_req->setHost(host);
                svr_req->setMsgId(UuId::uuId());
                svr_req->setMsgType(MsgType::REQ_SERVICE);
                svr_req->setServiceOptype(optype);
                for (auto &discoverer : it->second){
                    discoverer->_conn->send(svr_req);
                }
            } 

        private:
            std::mutex _mutex;
            // 建立服务于发现者之间的映射关系 用来表示一个服务都被哪些发现者发现过 一对多的关系
            std::unordered_map<std::string, std::set<Discoverer::ptr>> _method_discoverers;
            // 建立连接于发现者之间的映射关系 用来表示一个连接对应了哪个服务发现者 一对一的关系
            std::unordered_map<BaseConnection::ptr, Discoverer::ptr> _conn_discoverer;
        };

        class PDManager {
        public:
            using ptr = std::shared_ptr<PDManager>;
            PDManager()
            :_providers(std::make_shared<ProviderManager>()),
            _discoverers(std::make_shared<DiscovererManager>())
            {}
 
            // 服务操作请求 注册与发现的回调处理——注册到Dispatcher事件分发器中
            void onServiceRequest(const BaseConnection::ptr &conn, ServiceRequest::ptr &svr_req){
                ServiceOpType optype = svr_req->getServiceOpType();
                // 1.服务注册——a.新增服务提供者 b.服务上线通知 c.发送响应
                if (optype == ServiceOpType::SERVICE_REGISTRY){
                    auto host = svr_req->getHost();
                    server_logger->INFO("服务注册: '%s' -> %s:%d", 
                        svr_req->getMethod().c_str(), host.first.c_str(), host.second);
                    _providers->addProvider(conn, svr_req->getHost(), svr_req->getMethod());
                    _discoverers->onlineNotify(svr_req->getMethod(), svr_req->getHost());
                    return registerResponse(conn, svr_req);
                }

                // 2.服务发现——a.新增服务发现者 b.发送响应
                else if (optype == ServiceOpType::SERVICE_DISCOVERY){
                    server_logger->INFO("服务发现请求: '%s'", svr_req->getMethod().c_str());
                    _discoverers->addDiscoverer(conn, svr_req->getMethod());
                    return discoverResponse(conn, svr_req);
                }
                // 3.未知服务操作
                else{
                    server_logger->ERROR("未知服务操作类型: %d", static_cast<int>(optype));
                    return errorResponse(conn, svr_req);
                }
            }
            void onConnshutdown(const BaseConnection::ptr &conn){
                auto provider = _providers->getProvider(conn);
                if (provider.get() != nullptr){
                    server_logger->INFO("服务提供者下线: %s:%d (提供 %zu 个服务)", 
                        provider->_host.first.c_str(), provider->_host.second, provider->_methods.size());
                    // 获取下线的服务提供者的所有服务 给所有发现者发送服务下线通知
                    for (auto &method : provider->_methods){
                        server_logger->DEBUG("为服务 '%s' 发送下线通知", method.c_str());
                        _discoverers->offlineNotify(method, provider->_host);
                    }
                    _providers->delProvider(conn);
                }
                _discoverers->delDiscoverer(conn);
            }

        private:
            // 服务注册响应
            void registerResponse(const BaseConnection::ptr &conn, const ServiceRequest::ptr &svr_req){
                auto svr_rsp=MessageFactory::create<ServiceResponse>();
                svr_rsp->setMsgId(svr_req->getMsgId());
                svr_rsp->setMsgType(MsgType::RSP_SERVICE);
                svr_rsp->setServiceOptype(ServiceOpType::SERVICE_REGISTRY);
                svr_rsp->setRCode(RCode::RCODE_OK);
                conn->send(svr_rsp);
            }
            // 服务发现响应
            void discoverResponse(const BaseConnection::ptr &conn, const ServiceRequest::ptr &svr_req){
                auto svr_rsp=MessageFactory::create<ServiceResponse>();
                svr_rsp->setMsgId(svr_req->getMsgId());
                svr_rsp->setMsgType(MsgType::RSP_SERVICE);
                svr_rsp->setServiceOptype(ServiceOpType::SERVICE_DISCOVERY);
                std::vector<Address> hosts = _providers->methodHosts(svr_req->getMethod());
                if (hosts.empty()){
                    server_logger->INFO("服务发现: '%s' - 未找到可用服务提供者", svr_req->getMethod().c_str());
                    svr_rsp->setRCode(RCode::RCODE_NOT_FOUND_SERVICE);
                    return conn->send(svr_rsp);
                }
                else{
                    server_logger->INFO("服务发现: '%s' - 找到 %zu 个服务提供者", 
                        svr_req->getMethod().c_str(), hosts.size());
                    svr_rsp->setRCode(RCode::RCODE_OK);
                    svr_rsp->setMethod(svr_req->getMethod());
                    svr_rsp->setHosts(hosts);
                    return conn->send(svr_rsp);
                }
            }
            // 未知服务操作响应
            void errorResponse(const BaseConnection::ptr &conn, const ServiceRequest::ptr &svr_req){
                auto svr_rsp=MessageFactory::create<ServiceResponse>();
                svr_rsp->setMsgId(svr_req->getMsgId());
                svr_rsp->setMsgType(MsgType::RSP_SERVICE);
                svr_rsp->setServiceOptype(ServiceOpType::SERVICE_UNKNOW);
                svr_rsp->setRCode(RCode::RCODE_INVALID_OPTYPE);
                conn->send(svr_rsp);
            }

        private:
            ProviderManager::ptr _providers;
            DiscovererManager::ptr _discoverers;
        };
    }
}